using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace XiVo
{
  public partial class ScheduleControl : UserControl
  {
    // drawing variables
    int HighlightedItem = -1;
    ScheduleItem currentItem;
    public ScheduleItem CurrentItem
    {
      get { return currentItem; }
      set
      {
        currentItem = value;
        Refresh();
      }
    }
    EditScheduleItemForm EditForm = new EditScheduleItemForm();

    Brush bBlack = System.Drawing.Brushes.Black;
    Brush bWhite = System.Drawing.Brushes.White;
    Brush bGray = System.Drawing.Brushes.DarkGray;
    Brush bSelected = System.Drawing.Brushes.DarkBlue;
    Font font = new Font("Arial", 9);
    int[] cols = new int[] { 120, 30, 30, 120 };

    // the schedule itself
    public List<ScheduleItem> schedule = new List<ScheduleItem>();
    public int currentChannel;

    public delegate void ScheduleEvent(ScheduleControl sender, ScheduleEventArgs e);
    public event ScheduleEvent onScheduleEvent;

    public ScheduleControl()
    {
      InitializeComponent();
      timer_Tick();
    }

    private void ScheduleControl_Load(object sender, EventArgs e)
    {
      setScrollMax();
      EditForm.ItemSaved += new EditScheduleItemForm.ItemSavedEvent(EditForm_ItemSaved);
    }

    void EditForm_ItemSaved(object sender, ScheduleEventArgs e)
    {
      if (!schedule.Contains(e.Item))
        schedule.Add(e.Item);
      Refresh();
      timer_Tick();
    }

    // never let the timer go too long without a refresh - just in case
    const int timerMax = 30000;
    void SetTimer(DateTime nextEvent)
    {
      TimeSpan span = nextEvent - DateTime.Now;
      int duration;
      if (span.TotalMilliseconds <= timerMax)
        duration = (int)span.TotalMilliseconds;
      else
        duration = timerMax;
      if (duration <= 0)
        duration = 1;
      timer1.Interval = duration;
    }

    void setScrollMax()
    {
      int max = schedule.Count;
      if (vScrollBar1.Value > max)
        vScrollBar1.Value = max;
      vScrollBar1.Maximum = max;
    }

    // fire off the next event (if it's time), then set the next scheduled event on the schedule.
    // set timer to duration of this event so we can stop recording on time.
    bool running = false;
    public bool Running
    {
      get { return running; }
      set
      {
        running = value;
        timer_Tick();
      }
    }
    private void timer1_Tick(object sender, EventArgs e)
    {
      timer_Tick();
    }

    public void timer_Tick()
    {
      if (running)
      {
        if (currentItem.isCurrent() == false)
        {
          currentItem.setNextRepeat();
          ScheduleEventArgs se = new ScheduleEventArgs();
          se.Type = ScheduleEventArgs.EventTypeEnum.Stop;
          onScheduleEvent(this, se);
          running = false;
          schedule.Sort();
          CurrentItem = null;
        }
        else
          SetTimer(currentItem.EndTime);
      }

      ScheduleItem item = getNextItem();
      if (!running && item != null)
      {
        if (item.isCurrent())
        {
          CurrentItem = item;
          ScheduleEventArgs se = new ScheduleEventArgs();
          se.Item = item;
          se.Type = ScheduleEventArgs.EventTypeEnum.Start;
          if (onScheduleEvent != null)
            onScheduleEvent(this, se);
          SetTimer(item.EndTime);
          running = true;
        }
        else
          SetTimer(item.RecordStartTime());
      }

      timer1.Enabled = true;
      pbSchedule.Refresh();
    }

    //
    // gets the first active item on the schedule. 
    // an item is no longer active if its sceduled time has passed and there is no repeat time.
    // 
    public ScheduleItem getNextItem()
    {
      DateTime t = DateTime.MaxValue;
      ScheduleItem ret = null;
      int i = 0;
      while (i < schedule.Count)
      {
        ScheduleItem item = schedule[i];
        if (item.isCurrent()
          || item.isActive()
          && item.StartTime < t)
        {
          ret = schedule[i];
          t = item.StartTime;
        }
        ++i;
      }
      return ret;
    }

    private void bAdd_Click(object sender, EventArgs e)
    {
      EditForm.Item = new ScheduleItem(currentChannel);
      EditForm.Show();
      EditForm.Activate();
    }

    private void pbSchedule_Paint(object sender, PaintEventArgs e)
    {
      Graphics g = e.Graphics;
      int i = Common.bounds(0, schedule.Count - 1, vScrollBar1.Value);
      int y = 0;
      int x = 0;
      int col = 0;
      ScheduleItem item = null;

      g.DrawString("Time", font, bBlack, x, y);
      x += cols[col++];
      g.DrawString("Len", font, bBlack, x, y);
      x += cols[col++];
      g.DrawString("Ch", font, bBlack, x, y);
      x += cols[col++];
      g.DrawString("Name", font, bBlack, x, y);

      x = 0; col = 0;
      y += FontHeight + 2;
      for (int c = 0; c < cols.Length; ++c)
      {
        x += cols[col++];
        g.FillRectangle(bGray, x, y, 1, pbSchedule.Height);
      }
      g.FillRectangle(bBlack, 0, y, pbSchedule.Width, 1);

      y += 2;
      while (y < pbSchedule.Height && schedule.Count > 0 && i < schedule.Count)
      {
        item = schedule[i];

        Brush b = bBlack;
        if (i == HighlightedItem)
        {
          g.FillRectangle(bGray, 0, y, this.Width, font.Height);
          if (!item.Enabled) b = bWhite;
        }
        else if (item == currentItem)
        {
          g.FillRectangle(bSelected, 0, y, this.Width, font.Height);
          b = bWhite;
        }
        else if (!item.Enabled)
          b = bGray;

        x = 0; col = 0;
        g.DrawString(item.StartTime.ToString("MM-dd, hh:mm:ss t"), font, b, x, y);
        x += cols[col++];
        g.DrawString(item.Duration.ToString(), font, b, x, y);
        x += cols[col++];
        g.DrawString(item.Channel.ToString(), font, b, x, y);
        x += cols[col++];
        g.DrawString(item.Name, font, b, x, y);
        x += cols[col++];
        y += font.Height;
        ++i;
      }
    }

    public void SaveSchedule(string filename)
    {
      System.IO.StreamWriter outf = new System.IO.StreamWriter(filename);

      foreach (ScheduleItem item in schedule)
      {
        outf.Write(item.Channel.ToString() + '\t');
        outf.Write(item.DaysOfWeek[0].ToString() + '\t');
        outf.Write(item.DaysOfWeek[1].ToString() + '\t');
        outf.Write(item.DaysOfWeek[2].ToString() + '\t');
        outf.Write(item.DaysOfWeek[3].ToString() + '\t');
        outf.Write(item.DaysOfWeek[4].ToString() + '\t');
        outf.Write(item.DaysOfWeek[5].ToString() + '\t');
        outf.Write(item.DaysOfWeek[6].ToString() + '\t');
        outf.Write(item.Duration.ToString() + '\t');
        outf.Write(item.Enabled.ToString() + '\t'); ;
        outf.Write(item.Name.ToString() + '\t'); ;
        outf.Write(item.RepeatType.ToString() + '\t'); ;
        outf.Write(item.StartTime.ToString() + '\t'); ;
        outf.WriteLine();
      }
      outf.Close();
    }

    public void LoadSchedule(string filename)
    {
      System.IO.StreamReader inf = new System.IO.StreamReader(filename);
      string buffer = inf.ReadLine();
      string[] parts;

      while (buffer != null)
      {
        parts = buffer.Split('\t');
        ScheduleItem item = new ScheduleItem();
        item.Channel = int.Parse(parts[0]);
        item.DaysOfWeek[0] = bool.Parse(parts[1]);
        item.DaysOfWeek[1] = bool.Parse(parts[2]);
        item.DaysOfWeek[2] = bool.Parse(parts[3]);
        item.DaysOfWeek[3] = bool.Parse(parts[4]);
        item.DaysOfWeek[4] = bool.Parse(parts[5]);
        item.DaysOfWeek[5] = bool.Parse(parts[6]);
        item.DaysOfWeek[6] = bool.Parse(parts[7]);
        item.Duration = int.Parse(parts[8]);
        item.Enabled = bool.Parse(parts[9]);
        item.Name = parts[10];
        item.RepeatType = (ScheduleItem.RepeatTypeEnum)System.Enum.Parse(typeof(ScheduleItem.RepeatTypeEnum), parts[11]);
        item.StartTime = DateTime.Parse(parts[12]);
        item.setNextRepeat();
        schedule.Add(item);

        buffer = inf.ReadLine();
      }
      inf.Close();
      schedule.Sort();
    }

    private void pbSchedule_MouseMove(object sender, MouseEventArgs e)
    {
      int selected = (e.Y / font.Height + vScrollBar1.Value - 1);
      if (selected < schedule.Count)
      {
        HighlightedItem = selected;
        pbSchedule.Refresh();
      }

    }

    private void pbSchedule_MouseClick(object sender, MouseEventArgs e)
    {
      if (e.Button == MouseButtons.Left)
      {
        if (HighlightedItem < schedule.Count)
        {
          EditForm.Item = schedule[HighlightedItem];
          EditForm.Show();
          EditForm.Activate();
        }
      }
      else if (e.Button == MouseButtons.Right)
      {
        if (HighlightedItem >= 0 && HighlightedItem < schedule.Count)
        {
          ScheduleItem item = schedule[HighlightedItem];
          if (MessageBox.Show(null, "Delete item '" + item.Name + "'?", "Delete item", MessageBoxButtons.YesNo) == DialogResult.Yes)
          {
            if (item == currentItem)
              currentItem = null;
            schedule.Remove(item);
            timer_Tick();
          }
        }
      }
      pbSchedule.Refresh();
    }

    private void pbSchedule_MouseLeave(object sender, EventArgs e)
    {
      HighlightedItem = -1;
      pbSchedule.Refresh();
    }
  }

}
